﻿package org.openChart.sprite 
{
	import flash.display.AVM1Movie;
	import flash.display.JointStyle;
	import flash.geom.Point;
	import org.openChart.display.DisplayBaseObject;
	import flash.display.Sprite;
	
	/**
	 * The base class of sprite. The sprites must have a paint function to draw itself to screen.
	 * 
	 * @author Chongyuan
	 */
	public class BaseSprite extends Sprite implements BaseInterface
	{
		// The model of sprite.
		private var displayObject_:DisplayBaseObject;
		// The handler which is used to transfer the command to other sprite.
		private var commandHandler_:CommandHandler;
		
		/**
		 * The constructor of sprite. Paint funciton will be called as default in the constructor.
		 * 
		 * @param	displayObject The display model of the sprite.
		 * @param	commandHandler_ The command handler of the sprite.
		 */
		public function BaseSprite( displayObject:DisplayBaseObject, commandHandler_:CommandHandler ) 
		{
			this.displayObject_ = displayObject;
			this.commandHandler_ = commandHandler_;
			paint();
		}
		
		/**
		 * Painting the sprite to screen. All the child classes must override this function
		 */
		public function paint():void
		{
			
		}
		
		public function repaint():void
		{
			paint();
		}
		
		/**
		 * Draw an arc of an ellipse. The angle is from 0 to 360. We assume that angle_1 is small than angle_2,
		 * otherwise, you can make angle_1 be larger than angle_2, it does not matter, I will go on adding 360 to
		 * angle_2 unless making sure that angle_1 is less than angle_2. If angle_1 equals to angle_2, a ellipse 
		 * will be drawn.
		 * 
		 * @param	x The x value of the ellipse's centre position.
		 * @param	y The y value of the ellipse's centre position.
		 * @param	radius_x The length of radius witch parallels the x axis.
		 * @param	radius_y The lenght of radius witch parallels the y axis.
		 * @param	angle_1 The angle from which the arc begins.
		 * @param	angle_2 The angle with witch the are ends.
		 * @param	order The order to draw the arc. If the order is zero, drawing the arc from angle_1 to angle_2, and if the order is 1,
		 * drawing the arc form angle_2 to angle_1.
		 * @param	thickness The thickness of the arc.
		 * @param	color The color of the arc.
		 */
		protected function drawEllipseArc(x:Number, y:Number, radius_x:Number, radius_y:Number, angle_1:Number, angle_2:Number, order:uint, thickness:uint = 1, color:uint = 0):void
		{
			var PI:Number = Math.PI;
			var step:Number = PI / 90;
			var angle:Number;
			var beginAngle:Number = angle_1 / 180 * PI;
			var endAngle:Number = angle_2 / 180 * PI;
			// To make sure end angle larger than begin angle.
			while (beginAngle >= endAngle)
			{
				endAngle += 2 * PI;
			}
			
			graphics.lineStyle(thickness, color);
			if (order == 0) 
			{
				for (angle = beginAngle; angle < endAngle; angle += step )
				{
					graphics.lineTo(Math.cos(angle) * radius_x + x, y - Math.sin(angle) * radius_y);
				}
			}
			else if (order == 1)
			{
				for (angle = endAngle; angle > beginAngle; angle -= step )
				{
					graphics.lineTo(Math.cos(angle) * radius_x + x, y - Math.sin(angle) * radius_y);
				}
			}
		}
		
		/**
		 * Draw a line.
		 * 
		 * @param	x_1 The x value of begin position.
		 * @param	y_1 The y value of begin position.
		 * @param	x_2 The x value of end position.
		 * @param	y_2 The y value of end position.
		 * @param	thickness The thickness of line.
		 * @param	color The color of line.
		 * @param	alpha The transparency of line.
		 */
		protected function drawLine(x_1:Number, y_1:Number, x_2:Number, y_2:Number, thickness:uint = 1, color:uint = 0, alpha:uint = 1):void
		{
			graphics.lineStyle(thickness, color, alpha);
			graphics.moveTo(x_1, y_1);
			graphics.lineTo(x_2, y_2);
		}
		
		/**
		 * 
		 * @param	x The x value of position.
		 * @param	y The y value of position.
		 * @param	width The width of rectangle.
		 * @param	height The height of rectangle.
		 * @param	fill_color The color of rectangle.
		 * @param	fill_alpha The transparency of ractangle.
		 * @param	thickness The thickness of the rectangle's edge.
		 * @param	color The color of the rectangle's edge.
		 * @param	alpha The transparency of ractangle' edge.
		 */
		protected function fillRectangle(x:Number, y:Number, width:Number, height:Number, fill_color:uint, fill_alpha:Number=1, thickness:uint = 1, color:uint = 0, alpha:Number = 1):void
		{
			//trace(fill_alpha);
			graphics.beginFill(fill_color, fill_alpha);
			drawRectangle(x, y, width, height, color, alpha);
			graphics.endFill();
		}
		
		/**
		 * Draw a rectangle.
		 * 
		 * @param	x The x value of position.
		 * @param	y The y value of position.
		 * @param	width The width of rectangle.
		 * @param	height The height of rectangle.
		 * @param	thickness The thickness of the rectangle's edge.
		 * @param	color The color of the rectangle's edge.
		 * @param	alpha The transparency of ractangle' edge.
		 */
		protected function drawRectangle(x:Number, y:Number, width:Number, height:Number, thickness:uint = 1, color:uint = 0, alpha:Number = 1):void
		{
			graphics.lineStyle(thickness, color, alpha);
			var points:Array = [new Point(x, y), new Point(x + width, y), new Point(x + width, y + height), new Point(x, y + height) ];
			
			this.drawPolygon(points, thickness, color, alpha);
			
		}
		
		/**
		 * Fill a polygon.
		 * 
		 * @param	positions The points of the polygon.
		 * @param	fill_color The color of the polygon.
		 * @param	fill_alpha The transparency of polygon.
		 * @param	thickness The thickness of the polygon's edge.
		 * @param	color The color of the polygon's edge.
		 * @param	alpha The transparency of polygon' edge.
		 */
		protected function fillPolygon(positions:Array, fill_color:uint, fill_alpha:Number=1, thickness:uint = 1, color:uint = 0, alpha:Number = 1):void
		{
			if (positions && positions.length > 2)
			{
				graphics.beginFill(fill_color, fill_alpha);
				
				drawPolygon(positions, thickness, color, alpha);
				graphics.endFill();
			}
		}
		
		/**
		 * Draw a polygon.
		 * 
		 * @param	positions positions The points of the polygon.
		 * @param	he thickness of the polygon's edge.
		 * @param	color The color of the polygon's edge.
		 * @param	alpha The transparency of polygon' edge.
		 */
		protected function drawPolygon(positions:Array, thickness:uint = 0, color:uint = 0, alpha:Number = 1):void
		{
			
			if (positions && positions.length > 2)
			{
				
				graphics.lineStyle(thickness, color, alpha);
				var point_1:Point = positions[0] as Point;
				graphics.moveTo(point_1.x, point_1.y);
				for (var i:uint = 1; i < positions.length; i++ )
				{
					var point:Point = positions[i] as Point;
					graphics.lineTo(point.x, point.y);
				}
				graphics.lineTo(point_1.x, point_1.y);
				
			}
		}
		
		/**
		 * 
		 * @param	x
		 * @param	y
		 * @param	radius_x
		 * @param	radius_y
		 * @param	angle_1
		 * @param	angle_2
		 * @param	fill_color
		 * @param	fill_alpha
		 * @param	thickness
		 * @param	color
		 * @param	alpha = 1
		 */
		protected function fillSector(x:Number, y:Number, radius_x:Number, radius_y:Number, angle_1:Number, angle_2:Number, fill_color:uint, fill_alpha:Number = 1, thickness:uint = 0, color:uint = 0, alpha:Number = 1 ):void
		{
			graphics.beginFill(fill_color, fill_alpha);
			drawSector(x, y, radius_x, radius_y, angle_1, angle_2, thickness, color, alpha);
			graphics.endFill();
		}
		
		/**
		 * 
		 * @param	x
		 * @param	y
		 * @param	radius_x
		 * @param	radius_y
		 * @param	angle_1
		 * @param	angle_2
		 * @param	thickness
		 * @param	color
		 * @param	alpha = 1
		 */
		protected function drawSector(x:Number, y:Number, radius_x:Number, radius_y:Number, angle_1:Number, angle_2:Number, thickness:uint = 1, color:uint = 0, alpha:Number = 1 ):void
		{
			graphics.lineStyle(thickness, color, alpha);
			graphics.moveTo(x, y);
			graphics.lineTo(Math.cos(angle_1) * radius_x + x, y - Math.sin(angle_1) * radius_y);
			drawEllipseArc(x, y, radius_x, radius_y, angle_1, angle_2, 0, thickness, color);
			graphics.lineTo(Math.cos(angle_2) * radius_x + x, y - Math.sin(angle_2) * radius_y);
			graphics.lineTo(x, y);
		}
		
		protected function drawEllipse(x:Number, y:Number, radius_x:Number, radius_y:Number, thickness:uint = 0, color:uint = 0, alpha:Number = 1 ):void
		{
			graphics.lineStyle(thickness, color, alpha);
			graphics.drawEllipse(x - radius_x, y - radius_y, radius_x * 2, radius_y * 2);
		}
		
		protected function fillEllipse(x:Number, y:Number, radius_x:Number, radius_y:Number, fill_color:uint, fill_alpha:Number = 1, thickness:uint = 0, color:uint = 0, alpha:Number = 1 ):void
		{
			graphics.beginFill(fill_color, fill_alpha);
			drawEllipse(x, y, radius_x, radius_y, thickness, color, alpha);
			graphics.endFill();
		}
		
		/**
		 * Return the display model of the sprite.
		 */
		public function get displayObject():DisplayBaseObject
		{
			return this.displayObject_;
		}
		
		/**
		 * Return the command handler of the sprite.
		 */
		public function get commandHandler():CommandHandler
		{
			return this.commandHandler_;
		}
	}
	
}